#pragma once

#define LIST_ALLOC_SIZE 16

//Templated Vector List
template<typename TYPE>
class List
{
private:
	TYPE* m_list;
	int m_size;
	int m_used;
public:
	//ctor & dtor
	List() : m_list(0), m_size(0), m_used(0){}

	~List(){release();}

	//main functions
	void release()
	{
		if(m_list != 0)
			delete [] m_list;
		m_list = 0;
		m_size = 0;
		m_used = 0;
	}

	void clear()
	{
		//set size to zero
		//does NOT clear the memory if data if it's a pointer
		//will have to do that manually
		m_used = 0;
	}

	void insert(TYPE a_value, int a_index)
	{
		//check size; allocate more if used is larger or equal to current allocated size
		if(m_used >= m_size){resize(m_size+LIST_ALLOC_SIZE);}

		//increase the used size
		//do swap
		m_used++;
		TYPE t_value = m_list[a_index];
		m_list[a_index] = a_value;
		for(int i = a_index+1; i < m_used; i++)
		{
			TYPE temp = m_list[i];
			m_list[i] = t_value;
			t_value = temp;
		}
	}

	void insertFront(TYPE a_value)
	{
		//insert at index zero
		insert(a_value,0);
	}

	void insertBack(TYPE a_value)
	{
		//check size; allocate more if used is larger or equal to current allocated size
		if(m_used >= m_size){resize(m_size+LIST_ALLOC_SIZE);}

		//set the value at the end
		set(a_value,m_used);

		//increase the used size
		m_used++;
	}

	TYPE removeData(TYPE a_value)
	{
		for(int i = 0; i < m_used; i++)
		{
			if(m_list[i] == a_value)
			{
				return remove(i);
			}
		}
		return 0;
	}

	TYPE remove(int a_index)
	{
		//hold the removed data
		TYPE rmv = m_list[a_index];

		//shift all value starting from the give index down
		for(int i = a_index; i < m_used; i++)
			m_list[i] = m_list[i+1];

		//reduce size
		m_used--;

		//return the removed data
		return rmv;
	}

	TYPE removeFront()
	{
		//remove from index zero
		return remove(0);
	}

	TYPE removeBack()
	{
		//remove from last index
		return remove(used-1);
	}

	void insertSorted(TYPE a_value, bool a_duplicate = true)
	{
		//add if used is empty
		if(m_used == 0)
		{
			insertBack(a_value);
			return;
		}

		if(!a_duplicate)
		{
			for(int i = 0; i < m_used; i++)
			{
				if(m_list[i] == a_value)
					return;
			}
		}

		//start counting and comparing values
		//and insert in order
		int index = 0;
		for(int i = 0; i < m_used; i++)
		{
			if(a_value < m_list[i])
			{
				index = i;
				break;
			}
			else
			{
				index++;
			}
		}
		insert(a_value,index);
	}

	//setter functions
	void resize(int a_size, bool a_visible = false)
	{
		//allocate more memory and copy old to new
		TYPE* n_list = new TYPE[a_size];

		if(m_list != 0)
		{
			for(int i = 0; i < m_size; i++)
			{
				n_list[i] = m_list[i];
			}
			delete [] m_list;
			m_list = 0;
		}
		m_list = n_list;
		m_size = a_size;

		if(a_visible) m_used = m_size;
	}

	void set(TYPE a_value, int a_index)
	{
		//set the value at the given index
		m_list[a_index] = a_value;
	}

	//getter functions
	int size()
	{
		//return the used size
		return m_used;
	}

	bool empty()
	{
		return (m_used==0)?true:false;
	}

	TYPE get(int a_index)
	{
		//get the data from the given index
		return m_list[a_index];
	}

	TYPE getFront()
	{
		//get the data from the front
		return m_list[0];
	}

	TYPE getBack()
	{
		//get the data from the back
		return m_list[m_used-1];
	}

	TYPE** raw(int* size)
	{
		//grab the current raw array list
		return &m_list;
	}

	TYPE& operator[](int a_index)
	{
		return m_list[a_index];
	}
};